home *** CD-ROM | disk | FTP | other *** search
/ ShareWare OnLine 2 / ShareWare OnLine Volume 2 (CMS Software)(1993).iso / prog / xms.zip / XMS.ASM next >
Assembly Source File  |  1993-03-18  |  26KB  |  609 lines

  1. ;****************************************************************************
  2. ; XMS.ASM - Extended memory interface for QuickBASIC programs.
  3. ;
  4. ; (C) Copyright 1993 by One World Software. All rights reserved.
  5. ; Author: Robin Duffy.
  6. ;
  7. ; See the headers for each public routine on calling syntax and operating
  8. ; notes. Use of extended memory requires HIMEM.SYS to be installed via
  9. ; CONFIG.SYS and a 80286 or later processor. Each procedure may be
  10. ; called at any time, even if no XMS is installed on the host machine.
  11. ;
  12. ; .001 03/17/93 - Add XMS2XMS for copying from one XMS offset to another.
  13. ;
  14. ; Assembled with Turbo Assembler 2.5
  15. ;****************************************************************************
  16. .Model Medium, Basic
  17.  
  18. .Data
  19.  
  20. XError    db   80h                      ;Storage for errors, assumes no XMS
  21. XMSThere  dw   0                        ;XMS available flag, assumes no XMS
  22. XMove     dw   8 Dup(?)                 ;Buffer for array move routines
  23.  
  24. .Code
  25.  
  26. XMSDriver dw ?,?                        ;Local storage for HIMEM entry point
  27.  
  28.                     Public    InitXMS
  29. ;****************************************************************************
  30. ; Procedure to check for HIMEM.SYS and initialize a few things. This routine
  31. ; must be called prior to calling any of the other procedures.
  32. ;
  33. ; Syntax: CALL InitXMS(There%, MemSize%)
  34. ; Returns:     There% =  0 No XMS available
  35. ;                     = -1 XMS available
  36. ;
  37. ;            MemSize% = Size of available XMS in K bytes.
  38. ;                       Valid only if There% is not zero.
  39. ;****************************************************************************
  40. Proc InitXMS   Uses ES, There:Ptr Word, MemSize:Ptr Word
  41.  
  42.     Mov   AX,4300h                      ;Prepare to do installation check
  43.     Int   2fh                           ;Use the multiplex interrupt
  44.     Cmp   AL,80h                        ;Is HIMEM.SYS installed?
  45.     Jnz   InitExit                      ;Nope, get on out
  46.  
  47.     Mov   AX,4310h                      ;Get the driver entry point
  48.     Int   2fh
  49.  
  50.     Mov   CS:XMSDriver,BX               ;Store the offset of entry point
  51.     Mov   BX,ES
  52.     Mov   CS:XMSDriver[2],BX            ;And the segment of entry point
  53.  
  54.     Sub   BL,BL                         ;HIMEM does not clear this
  55.     Mov   AX,0800h
  56.     Call  DWord Ptr CS:XMSDriver        ;Find available extended memory size
  57.     Or    BL,BL                         ;Did an error occur?
  58.     Jnz   InitExit                      ;Yes, so get out now
  59.  
  60.     Cmp   AX,0                          ;Is there any left for us?
  61.     Jz    InitExit                      ;No, exit now
  62.  
  63.     Mov   BX,MemSize
  64.     Mov   [BX],AX                       ;Report the available size
  65.     Dec   XMSThere                      ;Mark our flag to -1 (XMS is good)
  66.     Mov   XError,0                      ;Clear the error variable
  67.  
  68. InitExit:
  69.     Mov   AX,XMSThere
  70.     Mov   BX,There
  71.     Mov   [BX],AX                       ;Report results to BASIC
  72.     Ret                                 ;And return
  73.  
  74. InitXMS   EndP
  75.  
  76.  
  77.                     Public    GetXMS
  78. ;***************************************************************************
  79. ; Procedure to allocate extended memory for the program. Because this is a
  80. ; function, it must be declared before it may be used.
  81. ; Syntax: Handle% = GetXMS(Size%)
  82. ;         where Handle% receives the XMS handle. All further references to
  83. ;         this block require this handle (much like DOS file handles). A
  84. ;         handle of 0 means an error allocating the memory.  This system
  85. ;         allows multiple blocks to be managed by the parent program.
  86. ;
  87. ;         Size% is the requested memory size in K bytes.
  88. ;***************************************************************************
  89. GetXMS    Proc Amount:Ptr
  90.  
  91.      Cmp  XMSThere,-1                   ;Any point in continuing?
  92.      Jnz  GetExit                       ;Nope.
  93.  
  94.      Mov BX,Amount
  95.      Mov  DX,[BX]                       ;Get the K requested by user
  96.  
  97.      Sub  BL,BL
  98.      Mov  AX,0900h
  99.      Call DWord Ptr CS:XMSDriver        ;Ask HIMEM for it
  100.      Mov  XError,BL                     ;Save error code
  101.  
  102.      Cmp  AL,1                          ;Was it allocated?
  103.      Jz   AllOK                         ;Yes, go return handle
  104.      Sub  DX,DX                         ;Otherwise return handle of zero
  105.  
  106. AllOK:
  107.      Mov  AX,DX                         ;Return handle as function output
  108.  
  109. GetExit:
  110.      Ret                                ;Return to BASIC
  111.  
  112. GetXMS    EndP
  113.  
  114.                     Public    FreeXMS
  115. ;***************************************************************************
  116. ; Procedure to release extended memory blocks.
  117. ;
  118. ; Syntax: CALL FreeXMS(Handle%)
  119. ;         where Handle% is the block handle assigned by GetXMS.  This should
  120. ;         be called prior to exiting your program. Unlike conventional
  121. ;         memory, extended memory is not automatically released by DOS
  122. ;         when the program ends. The memory remains allocated.
  123. ;***************************************************************************
  124. FreeXMS   Proc Uses SI, Handle:Ptr Word
  125.  
  126.      Cmp  XMSThere,-1                   ;Any point in continuing?
  127.      Jnz  FreeExit                      ;Nope.
  128.  
  129.      Mov  SI,Handle
  130.      Call CheckHandle                   ;Make sure it is a valid handle
  131.      Cmp  XError,0                      ;Error occur?
  132.      Jnz  FreeExit                      ;Yes, get out now!
  133.      
  134.      Mov  DX,[SI]                       ;Place user handle in DX
  135.      Sub  BL,BL
  136.      Mov  AX,0a00h
  137.      Call DWord Ptr CS:XMSDriver        ;Tell HIMEM to release the block
  138.      Mov  XError,BL                     ;Save error code
  139.      
  140. FreeExit:
  141.      Ret                                ;And return to BASIC
  142.  
  143. FreeXMS   EndP
  144.  
  145.  
  146.                     Public    Array2XMS
  147. ;****************************************************************************
  148. ; Procedure to move a block of memory from conventional to XMS memory.
  149. ;
  150. ;Syntax: CALL Array2XMS(BYVAL FromSeg%, BYVAL FromOffset%, Handle%, NumBytes&)
  151. ;                             or
  152. ;         CALL Array2XMS(SEG Array(1), Handle%, Numbytes&)
  153. ;
  154. ;         FromSeg% = Segment of source block
  155. ;         FromOffset% = Offset of source block
  156. ;         Handle% = XMS handle assigned by GetXMS
  157. ;         NumBytes& = number of bytes to move (must be even)
  158. ;                     if a constant is used, it must be declared long
  159. ;
  160. ;****************************************************************************
  161. Array2XMS Proc Uses SI, SSeg:Ptr Word, SOff:Ptr Word, Handle:Ptr Word,\
  162.                         Bytes:Ptr Word
  163.                                 
  164.      Cmp  XMSThere,-1                   ;Any point in continuing?
  165.      Jnz  Mov1Exit                      ;Nope.
  166.  
  167.      Mov  SI, Handle                    ;Pass handle address to CheckHandle
  168.      Call CheckHandle                   ;See if the handle is defined
  169.      Cmp  XError,0                      ;If error then exit
  170.      Jnz  Mov1Exit                      ;Exit with error already set
  171.  
  172.      Mov  SI,Offset XMove               ;Get location of our XMS structure
  173.  
  174.      Mov  BX,Bytes                      ;Starts with number of bytes to move
  175.      Mov  AX,[BX]                       ;Read low word
  176.      Mov  DX,[BX+2]                     ;Read high word (long integer)
  177.  
  178.      Test AX,1                          ;Is it odd?
  179.      Jz   IsEven                        ;No, it's OK
  180.      Dec  AX                            ;Force it even
  181.      
  182. IsEven:
  183.      Mov  [SI],AX                       ;Load low word of number of bytes
  184.      Mov  [SI+2],DX                     ;Load the high word
  185.  
  186.      Mov  Word Ptr [SI+4],0             ;Source handle is conventional memory
  187.      Mov  BX,SOff                       ;Load source offset
  188.      Mov  [SI+6],BX
  189.      Mov  BX,SSeg                       ;Load source segment
  190.      Mov  [SI+8],BX
  191.  
  192.      Mov  BX,Handle                     ;Load destination XMS handle
  193.      Mov  AX,[BX]
  194.      Mov  [SI+10],AX
  195.      
  196.      Mov  Word Ptr [SI+12],0           ;Offset 0 into XMS block
  197.      Mov  Word Ptr [SI+14],0
  198.  
  199.      Sub  BL,BL
  200.      Mov  AX,0b00h                      ;Ask HIMEM to do it for us
  201.      Call DWord Ptr CS:XMSDriver        
  202.      Mov  XError,BL                     ;Save the error code
  203.  
  204. Mov1Exit:
  205.      Ret                                ;Back to the BASIC's....
  206.  
  207. Array2XMS EndP
  208.  
  209.                     Public    XMS2Array
  210. ;***************************************************************************
  211. ; Procedure to move a block from XMS to conventional memory.
  212. ;
  213. ; Syntax: CALL XMS2Array(Handle%, BYVAL ToSeg%, BYVAL ToOffset%, NumBytes&)
  214. ;                             or
  215. ;         CALL Array2XMS(Handle%, SEG Array(1), Numbytes&)
  216. ;
  217. ;         Handle% = XMS handle assigned by GetXMS
  218. ;         ToSeg% = Segment of destination block
  219. ;         ToOff% = Offset of destination block
  220. ;         NumBytes& = number of bytes to move (must be even)
  221. ;****************************************************************************
  222. XMS2Array Proc Uses SI, Handle:Ptr Word, ToSeg:Ptr Word, ToOff:Ptr Word,\
  223.                         Bytes:Ptr Word
  224.  
  225.      Cmp  XMSThere,-1                   ;Any point in continuing?
  226.      Jnz  Mov2Exit                      ;Nope.
  227.  
  228.      Mov  SI, Handle                    ;Pass handle address to CheckHandle
  229.      Call CheckHandle                   ;See if the handle is defined
  230.      Cmp  XError,0                      ;If error then exit
  231.      Jnz  Mov2Exit                      ;Exit with error already set
  232.  
  233.      Mov  SI,Offset XMove               ;Get location of our XMS structure
  234.      
  235.      Mov  BX,Bytes                      ;Starts with number of bytes to move
  236.      Mov  AX,[BX]                       ;Read the low word
  237.      Mov  DX,[BX+2]                     ;Read the high word (long integer)
  238.      
  239.      Test AX,1                          ;Is it odd?
  240.      Jz   Is2Even                       ;They read the manual again!
  241.      Dec  AX                            ;Force it even
  242.  
  243. Is2Even:
  244.      Mov  [SI],AX                       ;Load low word
  245.      Mov  [SI+2],DX                     ;Now the high one
  246.  
  247.      Mov  BX,Handle                     ;Load the XMS source block handle
  248.      Mov  AX,[BX]
  249.      Mov  [SI+4],AX
  250.  
  251.      Mov  Word Ptr [SI+6],0            ;Offset 0 into XMS block
  252.      Mov  Word Ptr [SI+8],0
  253.  
  254.      Mov  Word Ptr [SI+10],0            ;Destination is conventional memory
  255.      Mov  BX,ToOff                      ;Load destination offset
  256.      Mov  [SI+12],BX
  257.      Mov  BX,ToSeg                      ;Load destination segment
  258.      Mov  [SI+14],BX
  259.  
  260.      Sub BL,BL
  261.      Mov  AX,0b00h                      ;Ask HIMEM to do it for us
  262.      Call DWord Ptr CS:XMSDriver        
  263.      Mov  XError,BL                     ;Save the error code
  264.  
  265. Mov2Exit:
  266.      Ret                                ;Back to the BASIC's....
  267.  
  268. XMS2Array EndP
  269.  
  270.                     Public XGetElement
  271. ;***************************************************************************
  272. ; Procedure to return any continuous portion of an array stored in XMS.
  273. ;
  274. ; Syntax: CALL GetElement(Handle%, Variable, EleLen%, EleNum%)
  275. ;    where Handle% - handle assigned by GetXMS
  276. ;          Variable - variable (TYPE, fixed string, or integer) to set
  277. ;          EleLen% - length of the variable in bytes
  278. ;          EleNum% - element number to retrieve
  279. ;
  280. ; Variable can be any variable type except a conventional string. It
  281. ; should be noted that EleLen% should be even. Also, this procedure
  282. ; assumes the first element of the array is element number one. That is,
  283. ; assume all arrays are one-based.
  284. ;***************************************************************************
  285. XGetElement     Proc Uses SI, Handle:Ptr Word, Vari:Ptr Word, EleLen:Ptr Word,\
  286.                              EleNum:Ptr Word
  287.  
  288.      Cmp  XMSThere,-1                   ;Any point in continuing?
  289.      Jnz  GEExit                        ;Nope.
  290.  
  291.      Mov  SI, Handle                    ;Pass handle address to CheckHandle
  292.      Call CheckHandle                   ;See if the handle is defined
  293.      Cmp  XError,0                      ;If error then exit
  294.      Jnz  GEExit                        ;Exit with error already set
  295.  
  296.      Mov  XError,0a7h                   ;Assume a syntax error
  297.      Mov  SI,Offset XMove               ;Location of our move buffer
  298.      Sub  DX,DX                         ;Make sure DX is zero (oops!)
  299.  
  300.      Mov  BX,EleLen                     ;Get the length of the variable
  301.      Mov  AX,[BX]                       ;Load into AX
  302.      Test AX,1                          ;Is it odd?
  303.      Jz   Is3Even                       ;No, it's OK.
  304.  
  305.      Dec  AX                            ;Make it even
  306.      Or   AX,AX                         ;It's not zero, is it?
  307.      Jnz  Is3Even                       ;No, it's OK.
  308.      Jmp  Short GEExit                  ;It is zero, leave now
  309.  
  310. Is3Even:
  311.      Mov  BX,EleNum                     ;Get the element to get
  312.      Mov  CX,[BX]                       ;into CX
  313.      Jcxz GEExit                        ;If element is 0, forget it
  314.  
  315.      Mov  XError,0                      ;We are OK here, clear error status
  316.      Mov  [SI],AX                       ;EleLen is number of bytes to move
  317.      Mov  [SI+2],DX                     ;High word should be zero.....
  318.  
  319.      Dec  CX                            ;Adjust CX to zero base
  320.      Mul  CX                            ;Find offset into block
  321.                                         ;DX:AX holds 32 bit offset into block
  322.      Mov  BX,Handle                     ;Find our source handle
  323.      Mov  CX,[BX]
  324.      Mov  [SI+4],CX                     ;Move handle into buffer
  325.      Mov  [SI+6],AX                     ;Low word of 32 bit offset
  326.      Mov  [SI+8],DX                     ;High word of offset
  327.  
  328.      Mov  Word Ptr [SI+10],0            ;Destination handle is convential mem
  329.      Mov  BX,Vari                       ;Get offset of variable from BASIC
  330.      Mov  [SI+12],BX                    ;Load offset into structure
  331.      Mov  [SI+14],DS                    ;Set segment to DS
  332.  
  333.      Sub BL,BL
  334.      Mov  AX,0b00h                      ;Ask HIMEM to do it for us
  335.      Call DWord Ptr CS:XMSDriver
  336.      Mov  XError,BL                     ;Save the error code
  337.  
  338. GEExit:
  339.      Ret                                ;Back to BASIC
  340.  
  341. XGetElement     EndP
  342.  
  343.  
  344.                     Public XSetElement
  345. ;***************************************************************************
  346. ; Procedure to set any continuous portion of an array stored in XMS.
  347. ;
  348. ; Syntax: CALL SetElement(Handle%, Variable, EleLen%, EleNum%)
  349. ;    where Handle% - handle assigned by GetXMS
  350. ;          Variable - variable (TYPE, fixed string, etc) to place in XMS
  351. ;          EleLen% - length of the variable in bytes
  352. ;          EleNum% - element number to write to
  353. ;
  354. ; Variable can be any variable type except a conventional string. It
  355. ; should be noted that EleLen% should be even. Also, this procedure
  356. ; assumes the first element of the array is element number one. That is,
  357. ; assume all arrays are one-based.
  358. ;***************************************************************************
  359. XSetElement    Proc Uses SI, Handle:Ptr Word, Vari:Ptr Word, EleLen:Ptr Word,\
  360.                              EleNum:Ptr Word
  361.  
  362.      Cmp  XMSThere,-1                   ;Any point in continuing?
  363.      Jnz  SEExit                        ;Nope.
  364.  
  365.      Mov  SI, Handle                    ;Pass handle address to CheckHandle
  366.      Call CheckHandle                   ;See if the handle is defined
  367.      Cmp  XError,0                      ;If error then exit
  368.      Jnz  SEExit                        ;Exit with error already set
  369.  
  370.      Mov  XError,0a7h                   ;Assume a syntax error
  371.      Mov  SI,Offset XMove               ;Location of our move buffer
  372.      Sub  DX,DX                         ;Make sure DX is zero (oops again!)
  373.  
  374.      Mov  BX,EleLen                     ;Get the length of the variable
  375.      Mov  AX,[BX]                       ;Load into AX
  376.      Test AX,1                          ;Is it odd?
  377.      Jz   Is4Even                       ;No, it's OK.
  378.  
  379.      Dec  AX                            ;Make it even
  380.      Or   AX,AX                         ;It's not zero, is it?
  381.      Jnz  Is4Even                       ;No, it's OK.
  382.      Jmp  Short SEExit                  ;It is zero, leave now
  383.  
  384. Is4Even:
  385.      Mov  BX,EleNum                     ;Get the element to write to
  386.      Mov  CX,[BX]                       ;into CX
  387.      Jcxz SEExit                        ;If element is 0, forget it
  388.  
  389.      Mov  XError,0                      ;We are OK here, clear error status
  390.      Mov  [SI],AX                       ;EleLen is number of bytes to move
  391.      Mov  [SI+2],DX                     ;High word should be zero
  392.  
  393.      Dec  CX                            ;Adjust CX to zero base
  394.      Mul  CX                            ;Find offset into block
  395.                                         ;DX:AX holds 32 bit offset into block
  396.      Mov  Word Ptr [SI+4],0             ;Source handle is convential mem
  397.      Mov  BX,Vari                       ;Get offset of variable from BASIC
  398.      Mov  [SI+6],BX                     ;Load offset into structure
  399.      Mov  [SI+8],DS                     ;Set segment to DS in structure
  400.  
  401.      Mov  BX,Handle                     ;Find our source handle
  402.      Mov  CX,[BX]
  403.      Mov  [SI+10],CX                    ;Move handle into buffer
  404.      Mov  [SI+12],AX                    ;Low word of 32 bit offset in buffer
  405.      Mov  [SI+14],DX                    ;High word of offset in buffer
  406.  
  407.      Sub BL,BL
  408.      Mov  AX,0b00h                      ;Ask HIMEM to do it for us
  409.      Call DWord Ptr CS:XMSDriver
  410.      Mov  XError,BL                     ;Save the error code
  411.  
  412. SEExit:
  413.      Ret                                ;Back to BASIC
  414.  
  415. XSetElement     EndP
  416.  
  417.                     Public    XMS2XMS
  418. ;****************************************************************************
  419. ; Procedure to copy one portion of XMS to another.
  420. ;
  421. ; Syntax: CALL XMS2XMS(Han1%, SourceOff&, Han2%, DestOff&, NumBytes&)
  422. ;
  423. ;    Where     Han1%      = Handle of source block of XMS
  424. ;              SourceOff& = 32 bit offset into block to start the copy
  425. ;              Han2%      = Handle of destination block of XMS
  426. ;              DestOff&   = 32 bit offset into block to copy to
  427. ;              Numbytes&  = Number of bytes to transfer
  428. ;
  429. ; Han1% and Han2% are XMS block handles as returned by GetXMS. You may use
  430. ; the same handle for each causing a transfer within the same block. If
  431. ; constants are used for the offsets, a "&" specifier must be appended to
  432. ; force a long reference. NumBytes& must be an even number.
  433. ;****************************************************************************
  434. XMS2XMS   Proc Uses SI, Han1:Ptr Word, SOff:Ptr Word, Han2:Ptr Word,\
  435.                         DOff:Ptr Word, NumBytes:Ptr Word
  436.      Cmp  XMSThere,-1                   ;Any point in continuing?
  437.      Jnz  XXExit                        ;Nope.
  438.  
  439.      Mov  SI, Han1                      ;Pass 1st handle address to CheckHandle
  440.      Call CheckHandle                   ;See if the handle is defined
  441.      Cmp  XError,0                      ;If error then exit
  442.      Jnz  XXExit                        ;Exit with error already set
  443.  
  444.      Mov  SI, Han2                      ;Pass 2nd handle address to CheckHandle
  445.      Call CheckHandle                   ;See if the handle is defined
  446.      Cmp  XError,0                      ;If error then exit
  447.      Jnz  XXExit                        ;Exit with error already set
  448.  
  449.      Mov  XError,0a7h                   ;Assume a syntax error
  450.      Mov  SI,Offset XMove               ;Location of our move buffer
  451.  
  452.      Mov  BX,Numbytes                   ;Get the amount to move
  453.      Mov  AX,[BX]                       ;Load low word in AX
  454.      Mov  DX,[BX+2]                     ;Load high word in DX
  455.      Test AX,1                          ;Is it odd?
  456.      Jz   Is5Even                       ;No, it's OK.
  457.  
  458.      Dec  AX                            ;Make it even
  459.      Or   AX,AX                         ;It's not zero, is it?
  460.      Jnz  Is5Even                       ;No, it's OK.
  461.      Or   DX,DX                         ;Is there a high word?
  462.      Jnz  Is5Even                       ;yes, it's OK
  463.      Jmp  Short XXExit                  ;It is zero, leave now
  464.  
  465. Is5Even:
  466.      Mov  XError,0                      ;We are OK here, clear error status
  467.      Mov  [SI],AX                       ;Low word number of bytes to move
  468.      Mov  [SI+2],DX                     ;High word number of bytes to move
  469.  
  470.      Mov  BX,Han1                       ;Get source handle
  471.      Mov  AX,[BX]
  472.      Mov  [SI+4],AX                     ;Load it in
  473.      Mov  BX,SOff                       ;Get source offset from BASIC
  474.      Mov  AX,[BX]
  475.      Mov  [SI+6],AX                     ;Load low word of source offset
  476.      Mov  AX,[BX+2]
  477.      Mov  [SI+8],AX                     ;Load high word of source offset
  478.  
  479.      Mov  BX,Han2                       ;Find our destination handle
  480.      Mov  AX,[BX]
  481.      Mov  [SI+10],AX                    ;Move handle into buffer
  482.  
  483.      Mov  BX,DOff                       ;Find the destination offset
  484.      Mov  AX,[BX]
  485.      Mov  [SI+12],AX                    ;Low word of 32 bit offset in buffer
  486.      Mov AX,[BX+2]
  487.      Mov  [SI+14],AX                    ;High word of offset in buffer
  488.  
  489.      Sub BL,BL
  490.      Mov  AX,0b00h                      ;Ask HIMEM to move it for us
  491.      Call DWord Ptr CS:XMSDriver
  492.      Mov  XError,BL                     ;Save the error code
  493.  
  494. XXExit:
  495.      Ret                                ;Back to BASIC
  496. XMS2XMS   EndP
  497.  
  498.  
  499.  
  500.  
  501.                     Public    XMSError
  502. ;****************************************************************************
  503. ; Procedure to report success of last XMS operation. Because this is a
  504. ; function, It must be declared before it may be used.
  505. ;
  506. ; Syntax: C% = XMSError%
  507. ;
  508. ;    returns C% = 0  Last operation successful
  509. ;            C% = -1 Last operation resulted in error
  510. ;
  511. ;    This function will always show an error if XMS is not available.
  512. ;****************************************************************************
  513. XMSError  Proc
  514.  
  515.      Mov  AX,-1                    ;Assume an error
  516.      Cmp  XMSThere,0               ;Is XMS available?
  517.      Jz   ExitErr                  ;No, exit now with error
  518.  
  519.      Mov  BL,XError                ;Load error byte in
  520.      Or   BL,BL                    ;Anything there?
  521.      Jnz  ExitErr                  ;Yes, report an error
  522.      Inc  AX                       ;Make it a 0 to show no error
  523.  
  524. ExitErr:
  525.      Ret                           ;Back to BASIC with output in AX
  526.  
  527. XMSError  EndP
  528.  
  529.                     Public    WhichXError
  530. ;***************************************************************************
  531. ; Procedure that returns the current value of XError. Because this is a
  532. ; function, it must be declared before it may be used. It should be noted
  533. ; that any sucessful call to any procedure in this file will clear XError.
  534. ;
  535. ; Syntax:  Code% = WhichXError%
  536. ;    where Code% receives the value of XError.
  537. ;***************************************************************************
  538. WhichXError    Proc
  539.  
  540.      Mov  AL,XError                     ;Load AL with the error
  541.      Xor  AH,AH                         ;Clear AH
  542.      Ret                                ;Return to BASIC
  543.  
  544. WhichXError    EndP
  545.  
  546.                     Public    SetXError
  547. ;****************************************************************************
  548. ; This procedure allows direct setting of the XError variable to force
  549. ; error codes. Useful for communications between modules.
  550. ;
  551. ; Syntax: CALL SetXError(ErrCode%)
  552. ;    where ErrCode% is a value between 0 - 255 inclusive.
  553. ;
  554. ; Note: If XMS is not installed, this function will not have any effect.
  555. ;****************************************************************************
  556. SetXError Proc ErrCode:Ptr Word
  557.  
  558.      Cmp  XMSThere,-1                   ;Can we set error codes?
  559.      Jnz  SetExit                       ;No, skip this
  560.      
  561.      Mov  BX,ErrCode                    ;Get the user's error code
  562.      Mov  AX,[BX]                       ;into AX
  563.      Mov  XError,AL                     ;Load it
  564.  
  565. SetExit:
  566.      Ret                                ;Back to BASIC
  567.  
  568. SetXError EndP
  569.  
  570. ;****************************************************************************
  571. ; CheckHandle - Procedure to test the validity of a user passed handle. For
  572. ;               some reason HIMEM.SYS does not seem to check the validity of
  573. ;               the handle on any function call but this one!  If not tested
  574. ;               an invalid handle will lock the machine.
  575. ;
  576. ; On Entry: SI - pointer to address of user passed handle
  577. ;
  578. ; On Exit: DX - block size associated with handle
  579. ;          XError - set to invalid handle if invalid, otherwise clear
  580. ;****************************************************************************
  581.  
  582. CheckHandle    Proc Near
  583.      Mov  DX,[SI]                       ;Put the handle in DX
  584.      Or   DX,DX                         ;Handle of zero?
  585.                                         ;Note: I test for a zero handle
  586.                                         ;becuase 0 is a valid handle for
  587.                                         ;HIMEM (conventional memory) but is
  588.                                         ;NOT valid for any user calls.
  589.      Jnz  DXOK                          ;It's not, go on
  590.      Mov  XError,0a2h                   ;Set "Invalid Handle" error
  591.      Jmp Short CHExit                   ;And exit
  592.  
  593. DXOK:
  594.      Sub  BL,BL                         ;Clear BL for HIMEM
  595.      Mov  XError,BL                     ;and the error code
  596.  
  597.      Mov  AX,0e00h
  598.      Call DWord Ptr CS:XMSDriver        ;Ask HIMEM about this handle
  599.  
  600.      Cmp  AX,1                          ;Was it successful?
  601.      Je   CHExit                        ;Yes, exit now
  602.      Mov  XError,BL                     ;Save the error code
  603.  
  604. CHExit:
  605.      Ret
  606. CheckHandle    EndP
  607.  
  608. End 
  609.